package org.papervision3d.core.utils;

//import flash.utils.Dictionary;

import org.papervision3d.core.geom.TriangleMesh3D;
import org.papervision3d.core.geom.renderables.Triangle3D;
import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.core.math.Plane3D;
import org.papervision3d.core.math.util.ClassificationUtil;
import org.papervision3d.core.math.util.TriangleUtil;
import org.papervision3d.core.proto.GeometryObject3D;
import nme.ObjectHash;

class MeshUtil
{
	public function new()
	{
		
	}
	
	public static function cutTriangleMesh(mesh:TriangleMesh3D, cuttingPlane:Plane3D):Array<TriangleMesh3D>
	{
		var geom:GeometryObject3D = mesh.geometry;
		var array:Array<TriangleMesh3D> = [];
		if(geom.faces.length){
			var triangleBucketA:Array<Triangle3D> = [];
			var triangleBucketB:Array<Triangle3D> = [];
			var vertBucketA:Array<Vertex3D> = [];
			var vertBucketB:Array<Vertex3D> = [];
			var vertCacheA:ObjectHash<Vertex3D, Vertex3D> = new ObjectHash<Vertex3D, Vertex3D>();
			var vertCacheB:ObjectHash<Vertex3D, Vertex3D> = new ObjectHash<Vertex3D, Vertex3D>();
			var triangle:Triangle3D;
			var nTriangle:Triangle3D;
			var oTris:Array<Triangle3D> = geom.faces;
			var vert:Vertex3D;
			var nVert:Vertex3D;
			var triClass:Int;
			var i:Int;
			var nTris:Array<Triangle3D> = [];
			for (triangle in oTris){
				var tris:Array<Triangle3D> = TriangleUtil.splitTriangleWithPlane(triangle, cuttingPlane);
				if(tris != null){
					for (nTriangle in tris){
						nTris.push(nTriangle);
					}
				}else{
					nTris.push(triangle);
				}
			}
			
			for (triangle in nTris){
				triClass = ClassificationUtil.classifyTriangle(triangle, cuttingPlane);
				if(triClass == ClassificationUtil.FRONT){
					triangleBucketA.push(triangle);
				}else if(triClass == ClassificationUtil.BACK){
					triangleBucketB.push(triangle);
				}
			}
			
			if(triangleBucketA.length > 0){
				for (triangle in triangleBucketA){
					for(i in 0...triangle.vertices.length){
						vert = triangle.vertices[i];
						if(!(nVert = vertCacheA.get(vert))){
							nVert = vert.clone();
							vertCacheA.set(vert, nVert);
						}
						
						vertBucketA.push(nVert);
						triangle.vertices[i] = nVert;
					}
					triangle.updateVertices();
				}
				var meshA:TriangleMesh3D = new TriangleMesh3D(mesh.material, vertBucketA, triangleBucketA);
				meshA.material = mesh.material;
				meshA.geometry.ready = true;	trace("OK");
				array.push(meshA);
			}
			 
			if(triangleBucketB.length > 0){
				for (triangle in triangleBucketB){
					for(i in 0...triangle.vertices.length){
						vert = triangle.vertices[i];
						if(!(nVert = vertCacheB.get(vert))){
							nVert = vert.clone();
							vertCacheB.set(vert, nVert);
						}
						nVert = vert.clone();
						vertBucketB.push(nVert);
						triangle.vertices[i] = nVert;
					}
					triangle.updateVertices();
				}
				var meshB:TriangleMesh3D = new TriangleMesh3D(mesh.material, vertBucketB, triangleBucketB);
				meshB.material = mesh.material;
				meshB.geometry.ready = true;
				array.push(meshB);
			}
			
			return array;
		}else{
			throw new Error("source geometry empty");
		}
		return array;
	}

}